using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using DataTypes;

namespace ProjectCastamere
{
    /// <summary>
    /// A game session starts when the player enters the 3d world and ends when they
    /// return to the main menu
    /// </summary>
    class GameSession : GameState
    {
        Model mapModel;
        Player player;
        PlacementGrid placementGrid;

        // utilise new effect class
        EffectClass basicEffect;

        // the profile to save persistance data of the game session to
        Profile profile;
        Path testPath;


        public enum State
        {
            CameraIntroTransition,
            PlayingGame
        }
        private State state;

        private CameraPath cameraPath;
        private float cameraTime;


        /// <summary>
        /// 
        /// </summary>
        /// <param name="levelName">the map to load, the map file should hold most of the data needed by a game session</param>
        /// <param name="profile">Used so that the game session can save persistance data, i.e. update statistics, add medals etc. to
        /// the save game profile, when a game session ends this profile can be saved back to file </param>
        public GameSession(Application app, String levelName, Profile profile)
            : base(app)
        {
            // TODO: load more data from xml
            this.profile = profile;
            player = new Player(application.GraphicsDevice.Viewport.AspectRatio);

            MapFile file = new MapFile();
            file = application.Content.Load<MapFile>("maps/testmap/testmap");

            // load the map model
            mapModel = application.Content.Load<Model>(file.MapModelFile);

            // load the placement grid
            placementGrid = new PlacementGrid(application.Content, file);

            // camera initially transitions in
            state = State.CameraIntroTransition;
            cameraTime = 0.0f;
            cameraPath = new CameraPath(file);

            // test the pathfinding
            testPath = placementGrid.CalculateRandomPath();

            Console.WriteLine("num points: " + testPath.GetPointCount());
            if(testPath != null)
              testPath.DebugPrint();

            // load the basic effect
            basicEffect = new EffectClass(app.GraphicsDevice);
        }

        public override void Input()
        {
            // check if the user has pressed pause
            if (InputManager.IsActionPressed(InputManager.GameActions.ExitGame))
            {
                application.PushState(new PauseMenu(application));
            }

            // process player input
            player.Input();
        }

        public override void Update()
        {
            //throw new NotImplementedException();
            switch (state)
            {
                case State.CameraIntroTransition:
                    {
                        // update the camera time
                        cameraTime += Constants.TimeStep;
                        if (cameraTime >= cameraPath.GetAnimationTime())
                        {
                            cameraTime = cameraPath.GetAnimationTime();
                            state = State.PlayingGame;
                        }
                    }
                    break;
            }
        }


        public override void Draw()
        {

            switch (state)
            {
                case State.CameraIntroTransition:
                    {
                        player.Camera.ViewMatrix = cameraPath.GetViewMatrix(cameraTime);
                    }
                    break;
            }

            /*
            // draw the level model using a BasicEffect
            BasicEffect effect = new BasicEffect(application.GraphicsDevice);
            effect.EnableDefaultLighting();
            effect.FogEnabled = true;
            effect.View = player.Camera.ViewMatrix;
            effect.Projection = player.Camera.ProjectionMatrix;
            foreach (ModelMesh mesh in mapModel.Meshes)
            {
                foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                {
                    pass.Apply();
                    mesh.Draw();
                }
            }
             * */


            Matrix[] transforms = new Matrix[mapModel.Bones.Count];
            //float aspectRatio = graphics.GraphicsDevice.Viewport.Width / graphics.GraphicsDevice.Viewport.Height;
            mapModel.CopyAbsoluteBoneTransformsTo(transforms);

            foreach (ModelMesh mesh in mapModel.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();

                    float aspect = application.GetAspectRatio();

                    effect.View = player.Camera.ViewMatrix;
                    effect.Projection = player.Camera.ProjectionMatrix;
                    effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateScale(0.01f);
                }
                mesh.Draw();
            }

            // draw the placement grid
            placementGrid.Draw(player.Camera, application.GraphicsDevice, testPath);


            //testPath.DebugDraw(player.Camera, application.GraphicsDevice);

            // setup the matrices
            Matrix view = player.Camera.ViewMatrix;
            Matrix projection = player.Camera.ProjectionMatrix;
            Matrix scale = Matrix.CreateScale(0.01f);

            // then draw the model now using the effect class
            //basicEffect.DrawModelWithBasicEffect(application, mapModel, view, projection, scale);
        }
    }
}
